<?php
/**
 * DMFramework
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @url http://dmframework.nl
 */

/**
 * With an ACL (Access Control List) you can specify which user group has
 * access to which resource, based on that you can create a login-system with
 * rights management.
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @package System.Library
 */
class Dmf_Acl
{
    /**
     * All roles
     *
     * @var array
     */
    private $_roles = array();
    
    /**
     * Read an ACL written in XML
     * 
     * @param string $xmlfile 
     * @throws Exception
     */
    public function readXml( $xmlfile )
    {
        if ( ! file_exists( $xmlfile ) )
        {
            throw new Dmf_Exception_FileNotFound( 'File: "' . $xmlfile . '" not found.' );
        }
        
        $content = file_get_contents( $xmlfile );
        $xml = new SimpleXMLElement( $content );
        
        foreach( $xml->role as $role )
        {
            $this->addRole( (string)$role['name'] );
            
            foreach( $role->resource as $resource )
            {
                foreach( $resource as $action )
                {
                    $this->allow( (string)$role['name'], (string)$resource['name'], (string)$action->getName() );
                }
            }
        }
    }
   
    /**
     * Shortcut
     *
     * @method addRole
     * @desc addGroup will be removed next release
     */
    public function addGroup( $name, $inherit = false )
    {
        return $this->addRole( $name, $inherit );
    }
   
    /**
     * Add group to ACL
     *
     * @param string $name
     * @param string $inherit
     * @return Acl_Group
     */
    public function addRole( $name, $inherit = false )
    {
        $role = ( $name instanceof Dmf_Acl_Role ) ? $name : new Dmf_Acl_Role( $name );
        $name = ( $name instanceof Dmf_Acl_Role ) ? $name->getName() : $name;
       
        if ( $inherit !== false )
        {
            $inheritRole = $this->_roles[ $inherit ];
           
            $role->setResources( $inheritRole->getResources() );
        }
        
        $this->_roles[ $name ] = $role;
    }
   
    /**
     * Allow a certain action
     *
     * @param string $name
     * @param string $controller
     * @param mixed $actions
     * @return Dmf_Acl
     * @throws Exception
     */
    public function allow( $role, $resources, $actions )
    {
        if ( ! isset( $this->_roles[ $role ] ) )
        {
            throw new Exception( 'Role: "' . $role . '" doesn\'t exist.' );
        }
        
        $actions = is_array( $actions ) ? $actions : array( $actions );
        $resources = is_array( $resources ) ? $resources : array( $resources );
        
        foreach( $resources as $resource )
        {
            $this->_roles[ $role ]->addResource( $resource, $actions );
        }
    }
   
    /**
     * Check if action is allowed
     *
     * @param string $role
     * @param string $resource
     * @param string $action
     * @return boolean
     */
    public function isAllowed( $role, $resource, $action )
    {
        return isset( $this->_roles[ $role ] ) ? $this->_roles[ $role ]->hasAccess( $resource, $action ) : false;
    }
   
    /**
     * Save ACL to registry
     *
     * @param string $name
     */
    public function save( $name = 'acl' )
    {
        Dmf_Registry::set( $name, $this );
    }
}